"""
Flink集群管理模块
提供Flink集群环境切换、状态监控等功能
"""

from flask import Blueprint, request, current_app
import requests
from app.utils.mysql_db import get_db_connection
from app.utils.logger import log_api_call, FlinkLogger

bp = Blueprint("flink_cluster", __name__, url_prefix="/api/flink/cluster")


@bp.get("/overview")
@log_api_call("flink_cluster.get_overview")
def get_cluster_overview():
    """
    获取指定Flink集群的概览信息
    支持通过env_id或config_name+host+port来获取
    """
    try:
        # 忽略flink_env参数，它是api.js自动添加的
        env_id = request.args.get('env_id', type=int)
        config_name = request.args.get('config_name')
        host = request.args.get('host')
        port = request.args.get('port')
        
        # 尝试将port转换为整数
        if port:
            try:
                port = int(port)
            except ValueError:
                return {"success": False, "error": f"端口号格式错误: {port}"}, 400
        
        current_app.logger.info(f"获取集群概览 - config_name: {config_name}, host: {host}, port: {port}")
        
        # 从数据库获取Flink环境配置
        with get_db_connection() as conn:
            with conn.cursor() as cursor:
                env_config = None
                
                if env_id:
                    # 通过ID查询
                    cursor.execute("""
                        SELECT id, config_name, host, port, protocol, username, password
                        FROM service_config 
                        WHERE id = %s AND service_type = 'flink' AND is_active = 1 AND is_deleted = 0
                    """, (env_id,))
                    env_config = cursor.fetchone()
                elif config_name and host and port:
                    # 通过配置名称和连接信息查询
                    cursor.execute("""
                        SELECT id, config_name, host, port, protocol, username, password
                        FROM service_config 
                        WHERE config_name = %s AND host = %s AND port = %s 
                              AND service_type = 'flink' AND is_active = 1 AND is_deleted = 0
                    """, (config_name, host, port))
                    env_config = cursor.fetchone()
                    
                    # 如果通过名称没找到，尝试只用host和port
                    if not env_config:
                        cursor.execute("""
                            SELECT id, config_name, host, port, protocol, username, password
                            FROM service_config 
                            WHERE host = %s AND port = %s 
                                  AND service_type = 'flink' AND is_active = 1 AND is_deleted = 0
                            LIMIT 1
                        """, (host, port))
                        env_config = cursor.fetchone()
                elif host and port:
                    # 如果只有host和port，尝试查询
                    cursor.execute("""
                        SELECT id, config_name, host, port, protocol, username, password
                        FROM service_config 
                        WHERE host = %s AND port = %s 
                              AND service_type = 'flink' AND is_active = 1 AND is_deleted = 0
                        LIMIT 1
                    """, (host, port))
                    env_config = cursor.fetchone()
                
                # 如果数据库中没找到，但有host和port，直接使用
                if not env_config and host and port:
                    env_config = {
                        'id': 0,
                        'config_name': config_name or f'{host}:{port}',
                        'host': host,
                        'port': port,
                        'protocol': request.args.get('protocol', 'http'),
                        'username': '',
                        'password': ''
                    }
                    current_app.logger.info(f"使用直接连接信息: {env_config}")
                elif not env_config:
                    return {"success": False, "error": "未找到指定的Flink环境配置或缺少必要参数"}, 404
        
        # 构建Flink REST API URL
        protocol = env_config['protocol'] or 'http'
        base_url = f"{protocol}://{env_config['host']}:{env_config['port']}"
        
        # 获取集群概览信息
        try:
            # 获取集群概览
            overview_url = f"{base_url}/overview"
            current_app.logger.info(f"请求Flink集群概览: {overview_url}")
            
            response = requests.get(overview_url, timeout=5)
            
            if response.status_code == 200:
                overview_data = response.json()
                
                # 获取TaskManager信息
                taskmanagers_url = f"{base_url}/taskmanagers"
                tm_response = requests.get(taskmanagers_url, timeout=5)
                taskmanagers = 0
                if tm_response.status_code == 200:
                    tm_data = tm_response.json()
                    taskmanagers = len(tm_data.get('taskmanagers', []))
                
                # 构建返回数据
                cluster_stats = {
                    "runningJobs": overview_data.get('jobs-running', 0),
                    "finishedJobs": overview_data.get('jobs-finished', 0),
                    "cancelledJobs": overview_data.get('jobs-cancelled', 0),
                    "failedJobs": overview_data.get('jobs-failed', 0),
                    "taskManagers": taskmanagers,
                    "totalSlots": overview_data.get('slots-total', 0),
                    "availableSlots": overview_data.get('slots-available', 0),
                    "version": overview_data.get('flink-version', 'unknown'),
                    "flinkCommit": overview_data.get('flink-commit', 'unknown')[:8] if overview_data.get('flink-commit') else 'unknown'
                }
                
                FlinkLogger.log_business_operation(
                    operation="get_cluster_overview",
                    details={"env_id": env_config.get('id'), "config_name": env_config['config_name']},
                    success=True
                )
                
                return {
                    "success": True,
                    "data": cluster_stats,
                    "message": "获取集群概览成功"
                }
            else:
                current_app.logger.error(f"Flink集群响应错误: {response.status_code}")
                return {
                    "success": False,
                    "error": f"Flink集群响应错误: {response.status_code}"
                }, 500
                
        except requests.exceptions.Timeout:
            current_app.logger.error(f"连接Flink集群超时: {base_url}")
            return {"success": False, "error": "连接Flink集群超时"}, 504
        except requests.exceptions.ConnectionError as e:
            current_app.logger.error(f"无法连接到Flink集群: {e}")
            return {"success": False, "error": "无法连接到Flink集群"}, 503
        except Exception as e:
            current_app.logger.error(f"获取集群信息失败: {e}")
            return {"success": False, "error": f"获取集群信息失败: {str(e)}"}, 500
            
    except Exception as e:
        current_app.logger.error(f"获取集群概览失败: {e}")
        return {"success": False, "error": f"服务器错误: {str(e)}"}, 500


@bp.get("/jobs")
@log_api_call("flink_cluster.get_jobs")
def get_cluster_jobs():
    """
    获取指定Flink集群的作业列表
    """
    try:
        env_id = request.args.get('env_id', type=int)
        if not env_id:
            return {"success": False, "error": "缺少环境ID参数"}, 400
        
        # 从数据库获取Flink环境配置
        with get_db_connection() as conn:
            with conn.cursor() as cursor:
                cursor.execute("""
                    SELECT id, config_name, host, port, protocol
                    FROM service_config 
                    WHERE id = %s AND service_type = 'flink' AND is_active = 1 AND is_deleted = 0
                """, (env_id,))
                
                env_config = cursor.fetchone()
                
                if not env_config:
                    return {"success": False, "error": "未找到指定的Flink环境配置"}, 404
        
        # 构建Flink REST API URL
        protocol = env_config['protocol'] or 'http'
        base_url = f"{protocol}://{env_config['host']}:{env_config['port']}"
        
        # 获取作业列表
        try:
            jobs_url = f"{base_url}/jobs/overview"
            current_app.logger.info(f"请求Flink作业列表: {jobs_url}")
            
            response = requests.get(jobs_url, timeout=5)
            
            if response.status_code == 200:
                jobs_data = response.json()
                
                FlinkLogger.log_business_operation(
                    operation="get_cluster_jobs",
                    details={"config_name": env_config['config_name'], "jobs_count": len(jobs_data.get('jobs', []))},
                    success=True
                )
                
                return {
                    "success": True,
                    "data": jobs_data.get('jobs', []),
                    "message": "获取作业列表成功"
                }
            else:
                return {
                    "success": False,
                    "error": f"Flink集群响应错误: {response.status_code}"
                }, 500
                
        except requests.exceptions.Timeout:
            return {"success": False, "error": "连接Flink集群超时"}, 504
        except requests.exceptions.ConnectionError:
            return {"success": False, "error": "无法连接到Flink集群"}, 503
        except Exception as e:
            current_app.logger.error(f"获取作业列表失败: {e}")
            return {"success": False, "error": f"获取作业列表失败: {str(e)}"}, 500
            
    except Exception as e:
        current_app.logger.error(f"获取作业列表失败: {e}")
        return {"success": False, "error": f"服务器错误: {str(e)}"}, 500


@bp.get("/taskmanagers")
@log_api_call("flink_cluster.get_taskmanagers")
def get_taskmanagers():
    """
    获取TaskManager列表（通过Flink官方API）
    """
    try:
        config_name = request.args.get('config_name')
        host = request.args.get('host')
        port = request.args.get('port')
        
        # 尝试将port转换为整数
        if port:
            try:
                port = int(port)
            except ValueError:
                return {"success": False, "error": f"端口号格式错误: {port}"}, 400
        
        # 从数据库获取Flink环境配置（与overview接口逻辑一致）
        with get_db_connection() as conn:
            with conn.cursor() as cursor:
                env_config = None
                
                if config_name and host and port:
                    cursor.execute("""
                        SELECT id, config_name, host, port, protocol
                        FROM service_config 
                        WHERE config_name = %s AND host = %s AND port = %s 
                              AND service_type = 'flink' AND is_active = 1 AND is_deleted = 0
                    """, (config_name, host, port))
                    env_config = cursor.fetchone()
                    
                    if not env_config and host and port:
                        cursor.execute("""
                            SELECT id, config_name, host, port, protocol
                            FROM service_config 
                            WHERE host = %s AND port = %s 
                                  AND service_type = 'flink' AND is_active = 1 AND is_deleted = 0
                            LIMIT 1
                        """, (host, port))
                        env_config = cursor.fetchone()
                elif host and port:
                    cursor.execute("""
                        SELECT id, config_name, host, port, protocol
                        FROM service_config 
                        WHERE host = %s AND port = %s 
                              AND service_type = 'flink' AND is_active = 1 AND is_deleted = 0
                        LIMIT 1
                    """, (host, port))
                    env_config = cursor.fetchone()
                
                if not env_config and host and port:
                    env_config = {
                        'id': 0,
                        'config_name': config_name or f'{host}:{port}',
                        'host': host,
                        'port': port,
                        'protocol': request.args.get('protocol', 'http')
                    }
                elif not env_config:
                    return {"success": False, "error": "未找到Flink环境配置"}, 404
        
        # 构建Flink REST API URL
        protocol = env_config['protocol'] or 'http'
        base_url = f"{protocol}://{env_config['host']}:{env_config['port']}"
        
        # 获取TaskManager列表
        try:
            tm_url = f"{base_url}/taskmanagers"
            current_app.logger.info(f"请求TaskManager列表: {tm_url}")
            response = requests.get(tm_url, timeout=5)
            
            if response.status_code == 200:
                tm_data = response.json()
                
                # 获取TaskManager详细信息
                taskmanagers = []
                for tm in tm_data.get('taskmanagers', []):
                    tm_detail = {
                        'id': tm.get('id'),
                        'path': tm.get('path'),
                        'dataPort': tm.get('dataPort'),
                        'timeSinceLastHeartbeat': tm.get('timeSinceLastHeartbeat'),
                        'slotsNumber': tm.get('slotsNumber'),
                        'freeSlots': tm.get('freeSlots'),
                        'hardware': tm.get('hardware', {}),
                        'memoryConfiguration': tm.get('memoryConfiguration', {})
                    }
                    taskmanagers.append(tm_detail)
                
                current_app.logger.info(f"获取到 {len(taskmanagers)} 个TaskManager")
                
                return {
                    "success": True,
                    "data": taskmanagers,
                    "message": f"获取到{len(taskmanagers)}个TaskManager"
                }
            else:
                return {
                    "success": False,
                    "error": f"Flink集群响应错误: {response.status_code}"
                }, 500
                
        except Exception as e:
            current_app.logger.error(f"获取TaskManager列表失败: {e}")
            return {"success": False, "error": f"获取TaskManager列表失败: {str(e)}"}, 500
            
    except Exception as e:
        current_app.logger.error(f"获取TaskManager列表失败: {e}")
        return {"success": False, "error": f"服务器错误: {str(e)}"}, 500


@bp.post("/switch-env")
@log_api_call("flink_cluster.switch_env")
def switch_environment():
    """
    切换Flink环境（更新默认环境）
    """
    try:
        data = request.get_json()
        env_id = data.get('env_id')
        
        if not env_id:
            return {"success": False, "error": "缺少环境ID参数"}, 400
        
        with get_db_connection() as conn:
            with conn.cursor() as cursor:
                # 检查环境是否存在
                cursor.execute("""
                    SELECT id, config_name 
                    FROM service_config 
                    WHERE id = %s AND service_type = 'flink' AND is_deleted = 0
                """, (env_id,))
                
                env_config = cursor.fetchone()
                
                if not env_config:
                    return {"success": False, "error": "未找到指定的Flink环境配置"}, 404
                
                # 更新系统配置中的默认Flink环境
                cursor.execute("""
                    UPDATE flink_cluster_system_config 
                    SET config_value = %s, modified_time = NOW()
                    WHERE config_key = 'default_flink_env_id'
                """, (str(env_id),))
                
                # 如果配置项不存在，则插入
                if cursor.rowcount == 0:
                    cursor.execute("""
                        INSERT INTO flink_cluster_system_config 
                        (config_key, config_group, config_value, config_type, description, is_active)
                        VALUES ('default_flink_env_id', 'flink', %s, 'int', '默认Flink环境ID', 1)
                    """, (str(env_id),))
                
                conn.commit()
                
                FlinkLogger.log_business_operation(
                    operation="switch_flink_env",
                    details={"env_id": env_id, "config_name": env_config['config_name']},
                    success=True
                )
                
                return {
                    "success": True,
                    "message": f"已切换到Flink环境: {env_config['config_name']}"
                }
                
    except Exception as e:
        current_app.logger.error(f"切换Flink环境失败: {e}")
        return {"success": False, "error": f"切换环境失败: {str(e)}"}, 500


@bp.get("/config/<int:env_id>")
@log_api_call("flink_cluster.get_config")
def get_environment_config(env_id):
    """
    获取指定Flink环境的配置信息
    """
    try:
        with get_db_connection() as conn:
            with conn.cursor() as cursor:
                cursor.execute("""
                    SELECT id, service_type, config_name, host, port, username, 
                           password, protocol, description, is_active,
                           created_time, updated_time
                    FROM service_config 
                    WHERE id = %s AND service_type = 'flink' AND is_deleted = 0
                """, (env_id,))
                
                env_config = cursor.fetchone()
                
                if not env_config:
                    return {"success": False, "error": "未找到指定的Flink环境配置"}, 404
                
                return {
                    "success": True,
                    "data": env_config,
                    "message": "获取配置成功"
                }
                
    except Exception as e:
        current_app.logger.error(f"获取Flink环境配置失败: {e}")
        return {"success": False, "error": f"获取配置失败: {str(e)}"}, 500


@bp.post("/start")
@log_api_call("flink_cluster.start")
def start_cluster():
    """
    启动Flink集群服务（支持选择性启动JobManager和/或TaskManager）
    TODO: 实现具体的SSH启动逻辑
    """
    try:
        data = request.get_json()
        host = data.get('host')
        services = data.get('services', ['jobmanager', 'taskmanager'])
        
        if not host:
            return {"success": False, "error": "缺少主机地址参数"}, 400
        
        current_app.logger.info(f"启动Flink服务 - 主机: {host}, 服务: {services}")
        
        # TODO: 实现SSH启动逻辑
        # 参考 flink_cluster_monitor.py 中的 restart_service 函数
        
        services_text = '、'.join([s.replace('jobmanager', 'JobManager').replace('taskmanager', 'TaskManager') for s in services])
        
        return {
            "success": True,
            "message": f"{services_text}启动命令已发送到 {host}（功能开发中）",
            "data": {"host": host, "services": services}
        }
        
    except Exception as e:
        current_app.logger.error(f"启动集群失败: {e}")
        return {"success": False, "error": f"启动失败: {str(e)}"}, 500


@bp.post("/stop")
@log_api_call("flink_cluster.stop")
def stop_cluster():
    """
    停止Flink集群服务（支持选择性停止JobManager和/或TaskManager）
    TODO: 实现具体的SSH停止逻辑
    """
    try:
        data = request.get_json()
        host = data.get('host')
        services = data.get('services', ['jobmanager', 'taskmanager'])
        
        if not host:
            return {"success": False, "error": "缺少主机地址参数"}, 400
        
        current_app.logger.info(f"停止Flink服务 - 主机: {host}, 服务: {services}")
        
        # TODO: 实现SSH停止逻辑
        # 参考 flink_cluster_monitor.py 中的 restart_service 函数
        
        services_text = '、'.join([s.replace('jobmanager', 'JobManager').replace('taskmanager', 'TaskManager') for s in services])
        
        return {
            "success": True,
            "message": f"{services_text}停止命令已发送到 {host}（功能开发中）",
            "data": {"host": host, "services": services}
        }
        
    except Exception as e:
        current_app.logger.error(f"停止集群失败: {e}")
        return {"success": False, "error": f"停止失败: {str(e)}"}, 500


@bp.post("/restart")
@log_api_call("flink_cluster.restart")
def restart_cluster():
    """
    重启Flink集群服务（支持选择性重启JobManager和/或TaskManager）
    TODO: 实现具体的SSH重启逻辑
    """
    try:
        data = request.get_json()
        host = data.get('host')
        services = data.get('services', ['jobmanager', 'taskmanager'])
        
        if not host:
            return {"success": False, "error": "缺少主机地址参数"}, 400
        
        current_app.logger.info(f"重启Flink服务 - 主机: {host}, 服务: {services}")
        
        # TODO: 实现SSH重启逻辑
        # 参考 flink_cluster_monitor.py 中的 restart_service 函数
        # 重启顺序：
        # 1. 停止TaskManager
        # 2. 停止JobManager  
        # 3. 等待8秒
        # 4. 启动JobManager
        # 5. 等待5秒
        # 6. 启动TaskManager
        
        services_text = '、'.join([s.replace('jobmanager', 'JobManager').replace('taskmanager', 'TaskManager') for s in services])
        
        return {
            "success": True,
            "message": f"{services_text}重启命令已发送到 {host}（功能开发中）",
            "data": {"host": host, "services": services}
        }
        
    except Exception as e:
        current_app.logger.error(f"重启集群失败: {e}")
        return {"success": False, "error": f"重启失败: {str(e)}"}, 500

